/**
 *
 * User: Zhikang.Peng
 * Date: 2018/07/27 15:40
 */
package references

import (
	"gitee.com/thghh/jvmgo/instructions/base"
	"gitee.com/thghh/jvmgo/rtda"
	"gitee.com/thghh/jvmgo/rtda/heap"
	"reflect"
)

type ATHROW struct {
	base.NoOperandsInstruction
}

func (self *ATHROW) Execute(frame *rtda.Frame) {
	ex := frame.OperandStack().PopReference()
	if ex == nil {
		panic("java.lang.NullPointExecute")
	}
	thread := frame.Thread()
	if !findAndGotoExecuteHandler(thread, ex) {
		handlerUncaughtException(thread, ex)
	}
}

/**
从当前帧开始，遍历Java虚拟机栈，查找方法的异常处理表。
假设遍历到帧F，如果在F对应的方法中找不到异常处理项，则把F
弹出，继续遍历。反之如果找到了异常处理项，在跳转到异常处理
代码之前，要先把F的操作数栈清空，然后把异常对象引用推入栈
顶
*/
func findAndGotoExecuteHandler(thread *rtda.Thread, ex *heap.Object) bool {
	for {
		frame := thread.CurrentFrame()
		pc := frame.NextPC() - 1
		handlerPC := frame.Method().FindExceptionHandler(ex.Class(), pc)
		if handlerPC > 0 {
			stack := frame.OperandStack()
			stack.Clear()
			stack.PushReference(ex)
			frame.SetNextPC(handlerPC)
			return true
		}
		thread.PopFrame()
		if thread.IsStackEmpty() {
			break
		}
	}
	return false
}

func handlerUncaughtException(thread *rtda.Thread, ex *heap.Object) {
	thread.ClearStack()
	jMsg := ex.GetRefVal("detailMessage", "Ljava/lang/String;")
	goMsg := heap.GoString(jMsg)
	println(ex.Class().JavaName() + ":" + goMsg)
	sets := reflect.ValueOf(ex.GetExtra())
	for i := 0; i < sets.Len(); i++ {
		set := sets.Index(i).Interface().(interface {
			String() string
		})
		println("\tat " + set.String())
	}
}
